/*
 * This file is part of the Boring Engine.
 *
 * Copyright (c) 2011 by pf5234 <pf5234@users.sourceforge.net>.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

package com.googlecode.boringengine;

import java.awt.event.KeyEvent;
import java.util.ArrayList;

public abstract class Menu<T> {

    private ArrayList<T> menuItems = new ArrayList<T>();
    private int current = 0, selected = 0;
    private int keyTimeout, loadTimeout;
    private boolean mouseDown;
    private static Sprite screen;
    protected boolean isClosed;
    protected int menuX, menuY, menuWidth, menuHeight, menuItemHeight;

    public void update() {
        if (keyTimeout > 0) keyTimeout--;
        if (loadTimeout > 0) loadTimeout--;
        if (Input.isPressed(KeyEvent.VK_ESCAPE) && keyTimeout == 0) {
            isClosed = true;
            return;
        }
        if (Input.isPressed(KeyEvent.VK_DOWN) && keyTimeout == 0) {
            selected++;
            selected %= menuItems.size();
            keyTimeout = 15;
        }
        if (Input.isPressed(KeyEvent.VK_UP) && keyTimeout == 0) {
            selected--;
            if (selected < 0) selected = menuItems.size() - 1;
            keyTimeout = 15;
        }
        Input.MouseInfo mouse = Input.getMouseInfo();
        if (mouse.mouseInWindow) {
            int y = mouse.y - menuY;
            if (y < 0) y -= menuItemHeight;
            y /= menuItemHeight;
            selected = current + y;
            if (selected < 0) selected = 0;
            if (selected >= menuItems.size()) selected = menuItems.size() - 1;
        }
        if (selected < current)
            current = selected;
        if (selected >= current + menuHeight / menuItemHeight)
            current = selected - menuHeight / menuItemHeight - 1;
        if (loadTimeout == 0 &&
                ((!mouse.buttonDown && mouseDown) || Input.isPressed(KeyEvent.VK_SPACE)))
        {
            menuItemClicked();
            loadTimeout = 30;
        }
        mouseDown = mouse.buttonDown;
    }

    public void draw() {
        int c = current, s = selected;
        if (c < 0) c = 0;
        for (int i = c; i < menuItems.size() && i < c + menuHeight / menuItemHeight; i++) {
            int x = menuX, y = (i - c) * menuItemHeight + menuY;
            Render.clip(x, y, menuWidth, menuItemHeight);
            draw(menuItems.get(i), x, y, s == i);
            Render.unClip();
        }
    }

    public static void drawScreen() {
        if (screen == null)
            screen = Render.createSpriteFromScreen(0, 0, 800, 600);
        Render.clearScreen();
        Render.drawSprite(screen);
        int alpha = Render.getAlpha();
        Render.setAlpha(128);
        Graphics.drawRect(0, 0, 800, 600, 0);
        Render.setAlpha(alpha);
    }

    public static void clearScreen() {
        screen = null;
    }

    public boolean isClosed() {
        return isClosed;
    }

    public void reset() {
        isClosed = false;
        keyTimeout = 15; loadTimeout = 15;
    }

    protected Menu(int x, int y, int width, int height, int itemHeight) {
        menuX = x; menuY = y; menuWidth = width; menuHeight = height;
        menuItemHeight = itemHeight;
    }

    protected void addItem(T item) {
        menuItems.add(item);
    }

    protected void addItem(T item, int index) {
        menuItems.add(index, item);
    }

    protected void removeItem(int index) {
        menuItems.remove(index);
    }

    protected void removeItem(T item) {
        menuItems.remove(item);
    }

    protected int numberOfItems() {
        return menuItems.size();
    }

    private final void menuItemClicked() {
        menuItemClicked(menuItems.get(selected));
    }

    protected abstract void menuItemClicked(T item);
    protected abstract void draw(T item, int x, int y, boolean isSelected);

}
